package tdt4240.iddqd.sprites;

import org.anddev.andengine.engine.handler.physics.PhysicsHandler;
import org.anddev.andengine.engine.handler.timer.ITimerCallback;
import org.anddev.andengine.engine.handler.timer.TimerHandler;
import org.anddev.andengine.entity.primitive.Rectangle;
import org.anddev.andengine.entity.sprite.AnimatedSprite;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;

import tdt4240.iddqd.Constants;

public class Player extends AnimatedSprite {

	private boolean animated;
	private boolean attacking=false;
	private boolean basicAttack=true;
	private boolean damageable=true;

	public int health;
	public int maxHealth;

	public Rectangle mActiveAttack;
	public PhysicsHandler physicsHandler;

	private Attack attackBasic = new Attack(70, 30, 0.25f, 0.5f);
	private Attack attackRanged = new Attack(5, 200, 0.1f, 0.75f);
	public Attack attack;

	public Player(float dx, float dy, TiledTextureRegion image){
		super(dx, dy, image);
		setCurrentTileIndex(0);
		setScale(Constants.SCALE_PLAYER);
		physicsHandler = new PhysicsHandler(this);
		registerUpdateHandler(physicsHandler);
		animated = false;
		attack = attackBasic;
		maxHealth = 100;
		health = maxHealth;
	}

	/**
	 * Play or stop animation of sprite
	 * @param bool If animation is wanted
	 * @param rotation The rotation of the player
	 */
	public void playAnimation(boolean bool, float rotation){
		if(animated ^ bool){
			animated = bool;
			if(animated){
				animate(100);	
			}else{
				stopAnimation();
			}
		}	
	}

	/**
	 * Animate sprite according to player rotation (currently unused)
	 * @param rot Rotation of the player
	 */
	public void determineSpriteOrientation(float rot){
		if(rot < Constants.CIRCLE_ONE_EIGHTH || rot > Constants.CIRCLE_SEVEN_EIGHTH){
			animate(new long[]{200, 200, 200}, 3, 5, true);
		}else if(rot >= Constants.CIRCLE_ONE_EIGHTH && rot < Constants.CIRCLE_THREE_EIGHTH){
			animate(new long[]{200, 200, 200}, 0, 2, true);
		}else if(rot >= Constants.CIRCLE_THREE_EIGHTH && rot < Constants.CIRCLE_FIVE_EIGHTH){
			animate(new long[]{200, 200, 200}, 9, 11, true);
		}else if(rot >= Constants.CIRCLE_FIVE_EIGHTH && rot < Constants.CIRCLE_SEVEN_EIGHTH){
			animate(new long[]{200, 200, 200}, 6, 8, true);
		}
	}

	/**
	 * Perform attack
	 */
	public void attack(){
		if(!attacking){
			attacking = true;
			float widthDisplacement = (getWidth()/2f)-(attack.width/2f);
			final Rectangle rect = new Rectangle(widthDisplacement,getHeight(), attack.width, attack.height);
			rect.setAlpha(0.3f);
			attachChild(rect);
			mActiveAttack=rect;

			TimerHandler spriteTimerHandler = new TimerHandler(attack.duration, new ITimerCallback()
			{                      
				@Override
				public void onTimePassed(final TimerHandler pTimerHandler)
				{
					detachChild(rect);
					mActiveAttack = null;
				}
			});

			TimerHandler cooldownTimerHandler = new TimerHandler(attack.cooldown, new ITimerCallback()
			{                      
				@Override
				public void onTimePassed(final TimerHandler pTimerHandler)
				{
					attacking=false;
				}
			});

			rect.registerUpdateHandler(spriteTimerHandler) ;
			registerUpdateHandler(cooldownTimerHandler);
		}
	}

	/**
	 * Take damage from an attack
	 * @param damage The amount of damage
	 * @param x X
	 * @param y Y
	 */
	public void takeDamage(int damage, float x, float y){
		if(damageable){
			health-=damage;
			damageable = false;

			TimerHandler hitstunTimerHandler = new TimerHandler(1f, new ITimerCallback()
			{                      
				@Override
				public void onTimePassed(final TimerHandler pTimerHandler)
				{
					damageable = true;
					Player.this.unregisterUpdateHandler(pTimerHandler);
				}
			});

			registerUpdateHandler(hitstunTimerHandler);
		}
		float dx = getX()-x;
		float dy = getY()-y;
		double norm = Math.sqrt(dx*dx + dy*dy);
		physicsHandler.setVelocity((float)(dx/norm)*400, (float)(dy/norm)*400);
	}

	/**
	 * Toggle selected weapon
	 */
	public void changeAttack(){
		if(basicAttack){
			basicAttack=false;
			attack=attackRanged;
		}else{
			basicAttack=true;
			attack=attackBasic;
		}
	}


}
